using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    /// <summary>
    /// 护肤产品仓储实现
    /// </summary>
    public class SkincareProductRepository : Repository<SkincareProduct>, ISkincareProductRepository
    {
        public SkincareProductRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincareProduct>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(p => p.UserId == userId).OrderByDescending(p => p.PurchaseDate).ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> GetByUserIdAndCategoryAsync(Guid userId, string category)
        {
            return await _dbSet.Where(p => p.UserId == userId && p.Category == category).ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> GetByUserIdAndBrandAsync(Guid userId, string brand)
        {
            return await _dbSet.Where(p => p.UserId == userId && p.Brand == brand).ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> GetByUserIdAndStatusAsync(Guid userId, string status)
        {
            return await _dbSet.Where(p => p.UserId == userId && p.Status == status).ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> GetByUserIdAndExpirationDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(p => p.UserId == userId && p.ExpirationDate >= startDate && p.ExpirationDate <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> GetExpiringSoonAsync(Guid userId, int days = 30)
        {
            var thresholdDate = DateTime.UtcNow.AddDays(days);
            return await _dbSet.Where(p => p.UserId == userId && p.ExpirationDate <= thresholdDate && p.Status != "UsedUp").ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> GetLowStockAsync(Guid userId)
        {
            return await _dbSet.Where(p => p.UserId == userId && p.RemainingAmount < 20 && p.Status != "UsedUp").ToListAsync();
        }

        public async Task<Dictionary<string, int>> GetCategoryStatisticsAsync(Guid userId)
        {
            var products = await _dbSet
                .Where(p => p.UserId == userId)
                .GroupBy(p => p.Category)
                .Select(g => new { Category = g.Key, Count = g.Count() })
                .ToListAsync();

            return products.ToDictionary(p => p.Category, p => p.Count);
        }

        public async Task<Dictionary<string, int>> GetBrandStatisticsAsync(Guid userId)
        {
            var products = await _dbSet
                .Where(p => p.UserId == userId)
                .GroupBy(p => p.Brand)
                .Select(g => new { Brand = g.Key, Count = g.Count() })
                .ToListAsync();

            return products.ToDictionary(p => p.Brand, p => p.Count);
        }
    }

    /// <summary>
    /// 护肤记录仓储实现
    /// </summary>
    public class SkincareRecordRepository : Repository<SkincareRecord>, ISkincareRecordRepository
    {
        public SkincareRecordRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincareRecord>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(r => r.UserId == userId).OrderByDescending(r => r.RecordDate).ToListAsync();
        }

        public async Task<IEnumerable<SkincareRecord>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(r => r.UserId == userId && r.RecordDate >= startDate && r.RecordDate <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<SkincareRecord>> GetByUserIdAndTimeOfDayAsync(Guid userId, string timeOfDay)
        {
            return await _dbSet.Where(r => r.UserId == userId && r.TimeOfDay == timeOfDay).ToListAsync();
        }

        public async Task<IEnumerable<SkincareRecord>> GetByProductIdAsync(Guid productId)
        {
            return await _dbSet.Where(r => r.ProductId == productId).OrderByDescending(r => r.RecordDate).ToListAsync();
        }

        public async Task<SkincareRecord?> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet.FirstOrDefaultAsync(r => r.UserId == userId && r.RecordDate.Date == date.Date);
        }

        public async Task<Dictionary<DateTime, int>> GetDailyRoutineCountAsync(Guid userId, int days = 30)
        {
            var endDate = DateTime.UtcNow.Date;
            var startDate = endDate.AddDays(-days);

            var records = await _dbSet
                .Where(r => r.UserId == userId && r.RecordDate >= startDate && r.RecordDate <= endDate)
                .ToListAsync();

            var result = new Dictionary<DateTime, int>();
            for (var date = startDate; date <= endDate; date = date.AddDays(1))
            {
                var dayRecords = records.Where(r => r.RecordDate.Date == date.Date);
                result[date] = dayRecords.Count();
            }

            return result;
        }

        public async Task<Dictionary<string, int>> GetTimeOfDayStatisticsAsync(Guid userId, int days = 30)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var records = await _dbSet
                .Where(r => r.UserId == userId && r.RecordDate >= startDate && r.RecordDate <= endDate)
                .GroupBy(r => r.TimeOfDay)
                .Select(g => new { TimeOfDay = g.Key, Count = g.Count() })
                .ToListAsync();

            return records.ToDictionary(r => r.TimeOfDay, r => r.Count);
        }

        public async Task<Dictionary<Guid, int>> GetProductUsageStatisticsAsync(Guid userId, int days = 30)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var records = await _dbSet
                .Where(r => r.UserId == userId && r.RecordDate >= startDate && r.RecordDate <= endDate)
                .GroupBy(r => r.ProductId)
                .Select(g => new { ProductId = g.Key, Count = g.Count() })
                .ToListAsync();

            return records.ToDictionary(r => r.ProductId, r => r.Count);
        }
    }

    /// <summary>
    /// 护肤记录项仓储实现
    /// </summary>
    public class SkincareRecordItemRepository : Repository<SkincareRecordItem>, ISkincareRecordItemRepository
    {
        public SkincareRecordItemRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincareRecordItem>> GetByRecordIdAsync(Guid recordId)
        {
            return await _dbSet.Where(i => i.RecordId == recordId).ToListAsync();
        }

        public async Task<IEnumerable<SkincareRecordItem>> GetByProductIdAsync(Guid productId)
        {
            return await _dbSet.Where(i => i.ProductId == productId).ToListAsync();
        }

        public async Task<Dictionary<Guid, List<SkincareRecordItem>>> GetByRecordIdsAsync(IEnumerable<Guid> recordIds)
        {
            var items = await _dbSet.Where(i => recordIds.Contains(i.RecordId)).ToListAsync();
            
            return items
                .GroupBy(i => i.RecordId)
                .ToDictionary(g => g.Key, g => g.ToList());
        }

        public async Task<Dictionary<Guid, int>> GetProductUsageCountAsync(Guid userId, int days = 30)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var recordIds = await _context.Set<SkincareRecord>()
                .Where(r => r.UserId == userId && r.RecordDate >= startDate && r.RecordDate <= endDate)
                .Select(r => r.Id)
                .ToListAsync();

            var items = await _dbSet
                .Where(i => recordIds.Contains(i.RecordId))
                .GroupBy(i => i.ProductId)
                .Select(g => new { ProductId = g.Key, Count = g.Count() })
                .ToListAsync();

            return items.ToDictionary(i => i.ProductId, i => i.Count);
        }
    }

    /// <summary>
    /// 皮肤状态仓储实现
    /// </summary>
    public class SkinConditionRepository : Repository<SkinCondition>, ISkinConditionRepository
    {
        public SkinConditionRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkinCondition>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(c => c.UserId == userId).OrderByDescending(c => c.RecordDate).ToListAsync();
        }

        public async Task<IEnumerable<SkinCondition>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(c => c.UserId == userId && c.RecordDate >= startDate && c.RecordDate <= endDate).ToListAsync();
        }

        public async Task<SkinCondition?> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet.FirstOrDefaultAsync(c => c.UserId == userId && c.RecordDate.Date == date.Date);
        }

        public async Task<IEnumerable<SkinCondition>> GetBySkinTypeAsync(Guid userId, string skinType)
        {
            return await _dbSet.Where(c => c.UserId == userId && c.SkinType == skinType).ToListAsync();
        }

        public async Task<IEnumerable<SkinCondition>> GetByConcernAsync(Guid userId, string concern)
        {
            return await _dbSet.Where(c => c.UserId == userId && c.Concerns.Contains(concern)).ToListAsync();
        }

        public async Task<Dictionary<string, int>> GetSkinTypeStatisticsAsync(Guid userId, int days = 90)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var conditions = await _dbSet
                .Where(c => c.UserId == userId && c.RecordDate >= startDate && c.RecordDate <= endDate)
                .GroupBy(c => c.SkinType)
                .Select(g => new { SkinType = g.Key, Count = g.Count() })
                .ToListAsync();

            return conditions.ToDictionary(c => c.SkinType, c => c.Count);
        }

        public async Task<Dictionary<string, int>> GetConcernStatisticsAsync(Guid userId, int days = 90)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var conditions = await _dbSet
                .Where(c => c.UserId == userId && c.RecordDate >= startDate && c.RecordDate <= endDate)
                .ToListAsync();

            var result = new Dictionary<string, int>();
            foreach (var condition in conditions)
            {
                if (!string.IsNullOrEmpty(condition.Concerns))
                {
                    var concerns = condition.Concerns.Split(',', StringSplitOptions.RemoveEmptyEntries);
                    foreach (var concern in concerns)
                    {
                        var trimmedConcern = concern.Trim();
                        if (result.ContainsKey(trimmedConcern))
                            result[trimmedConcern]++;
                        else
                            result[trimmedConcern] = 1;
                    }
                }
            }

            return result;
        }

        public async Task<SkinCondition?> GetLatestByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(c => c.UserId == userId).OrderByDescending(c => c.RecordDate).FirstOrDefaultAsync();
        }
    }

    /// <summary>
    /// 护肤计划仓储实现
    /// </summary>
    public class SkincarePlanRepository : Repository<SkincarePlan>, ISkincarePlanRepository
    {
        public SkincarePlanRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincarePlan>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(p => p.UserId == userId).OrderByDescending(p => p.CreatedAt).ToListAsync();
        }

        public async Task<SkincarePlan?> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet.FirstOrDefaultAsync(p => p.UserId == userId && p.StartDate.Date <= date.Date && p.EndDate.Date >= date.Date);
        }

        public async Task<IEnumerable<SkincarePlan>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(p => p.UserId == userId && 
                ((p.StartDate >= startDate && p.StartDate <= endDate) || 
                 (p.EndDate >= startDate && p.EndDate <= endDate) ||
                 (p.StartDate <= startDate && p.EndDate >= endDate)))
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlan>> GetBySkinTypeAsync(string skinType)
        {
            return await _dbSet.Where(p => p.SkinType == skinType || p.SkinType == "all").ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlan>> GetByLifeStageAsync(string lifeStage)
        {
            return await _dbSet.Where(p => p.LifeStage == lifeStage || p.LifeStage == "all").ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlan>> GetActivePlansAsync(Guid userId)
        {
            var today = DateTime.UtcNow.Date;
            return await _dbSet.Where(p => p.UserId == userId && p.StartDate.Date <= today && p.EndDate.Date >= today).ToListAsync();
        }
    }

    /// <summary>
    /// 护肤计划项仓储实现
    /// </summary>
    public class SkincarePlanItemRepository : Repository<SkincarePlanItem>, ISkincarePlanItemRepository
    {
        public SkincarePlanItemRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincarePlanItem>> GetByPlanIdAsync(Guid planId)
        {
            return await _dbSet.Where(i => i.PlanId == planId).OrderBy(i => i.Step).ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlanItem>> GetByPlanIdAndTimeOfDayAsync(Guid planId, string timeOfDay)
        {
            return await _dbSet.Where(i => i.PlanId == planId && i.TimeOfDay == timeOfDay).OrderBy(i => i.Step).ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlanItem>> GetByProductIdAsync(Guid productId)
        {
            return await _dbSet.Where(i => i.ProductId == productId).ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlanItem>> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            var planIds = await _context.Set<SkincarePlan>()
                .Where(p => p.UserId == userId && p.StartDate.Date <= date.Date && p.EndDate.Date >= date.Date)
                .Select(p => p.Id)
                .ToListAsync();

            return await _dbSet.Where(i => planIds.Contains(i.PlanId)).OrderBy(i => i.Step).ToListAsync();
        }

        public async Task<Dictionary<Guid, List<SkincarePlanItem>>> GetByPlanIdsAsync(IEnumerable<Guid> planIds)
        {
            var items = await _dbSet.Where(i => planIds.Contains(i.PlanId)).ToListAsync();
            
            return items
                .GroupBy(i => i.PlanId)
                .ToDictionary(g => g.Key, g => g.ToList());
        }

        public async Task<Dictionary<string, List<SkincarePlanItem>>> GetByTimeOfDayAsync(Guid planId)
        {
            var items = await _dbSet.Where(i => i.PlanId == planId).ToListAsync();
            
            return items
                .GroupBy(i => i.TimeOfDay)
                .ToDictionary(g => g.Key, g => g.ToList());
        }
    }

    /// <summary>
    /// 护肤成分仓储实现
    /// </summary>
    public class SkincareIngredientRepository : Repository<SkincareIngredient>, ISkincareIngredientRepository
    {
        public SkincareIngredientRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<SkincareIngredient?> GetByNameAsync(string name)
        {
            return await _dbSet.FirstOrDefaultAsync(i => i.Name == name);
        }

        public async Task<IEnumerable<SkincareIngredient>> GetByCategoryAsync(string category)
        {
            return await _dbSet.Where(i => i.Category == category).ToListAsync();
        }

        public async Task<IEnumerable<SkincareIngredient>> GetByFunctionAsync(string function)
        {
            return await _dbSet.Where(i => i.Function.Contains(function)).ToListAsync();
        }

        public async Task<IEnumerable<SkincareIngredient>> GetBySafetyRatingAsync(int minRating, int maxRating)
        {
            return await _dbSet.Where(i => i.SafetyRating >= minRating && i.SafetyRating <= maxRating).ToListAsync();
        }

        public async Task<IEnumerable<SkincareIngredient>> GetBySkinTypeAsync(string skinType)
        {
            return await _dbSet.Where(i => i.SuitableFor.Contains(skinType) || i.SuitableFor == "all").ToListAsync();
        }

        public async Task<IEnumerable<SkincareIngredient>> GetByConcernAsync(string concern)
        {
            return await _dbSet.Where(i => i.Targets.Contains(concern)).ToListAsync();
        }

        public async Task<IEnumerable<SkincareIngredient>> SearchAsync(string keyword)
        {
            return await _dbSet.Where(i => 
                i.Name.Contains(keyword) || 
                i.Description.Contains(keyword) || 
                i.Category.Contains(keyword) ||
                i.Function.Contains(keyword))
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareIngredient>> GetRecommendedAsync(string skinType, string concern)
        {
            return await _dbSet.Where(i => 
                (i.SuitableFor.Contains(skinType) || i.SuitableFor == "all") &&
                (i.Targets.Contains(concern) || i.Targets == "general"))
                .ToListAsync();
        }
    }

    /// <summary>
    /// 产品成分仓储实现
    /// </summary>
    public class ProductIngredientRepository : Repository<ProductIngredient>, IProductIngredientRepository
    {
        public ProductIngredientRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<ProductIngredient>> GetByProductIdAsync(Guid productId)
        {
            return await _dbSet.Where(i => i.ProductId == productId).OrderBy(i => i.Concentration).ToListAsync();
        }

        public async Task<IEnumerable<ProductIngredient>> GetByIngredientIdAsync(Guid ingredientId)
        {
            return await _dbSet.Where(i => i.IngredientId == ingredientId).ToListAsync();
        }

        public async Task<Dictionary<Guid, List<ProductIngredient>>> GetByProductIdsAsync(IEnumerable<Guid> productIds)
        {
            var items = await _dbSet.Where(i => productIds.Contains(i.ProductId)).ToListAsync();
            
            return items
                .GroupBy(i => i.ProductId)
                .ToDictionary(g => g.Key, g => g.ToList());
        }

        public async Task<Dictionary<Guid, List<ProductIngredient>>> GetByIngredientIdsAsync(IEnumerable<Guid> ingredientIds)
        {
            var items = await _dbSet.Where(i => ingredientIds.Contains(i.IngredientId)).ToListAsync();
            
            return items
                .GroupBy(i => i.IngredientId)
                .ToDictionary(g => g.Key, g => g.ToList());
        }
    }
}